//小白数据库
//表信息
package xbdb

/*
var bytespool = sync.Pool{
	New: func() interface{} {
		return new([][]byte)
	},
}
*/
import (
	"bytes"
	"strings"

	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/iterator"
	"github.com/syndtr/goleveldb/leveldb/util"
)

type Select struct {
	Db     *leveldb.DB
	Tbname string
}

var (
	iterFixed map[bool]func(iter iterator.Iterator) bool //起始位置。升序，first；降序，last
	itermove  map[bool]func(iter iterator.Iterator) bool //移动netx, prev
)

func First(iter iterator.Iterator) bool {
	return iter.First()
}
func Last(iter iterator.Iterator) bool {
	return iter.Last()
}
func Prev(iter iterator.Iterator) bool {
	return iter.Prev()
}
func Next(iter iterator.Iterator) bool {
	return iter.Next()
}

func NewSelect(tbname string, db *leveldb.DB) *Select { //*leveldb.DB {

	iterFixed = make(map[bool]func(iter iterator.Iterator) bool, 2)
	iterFixed[true] = First
	iterFixed[false] = Last
	itermove = make(map[bool]func(iter iterator.Iterator) bool, 2)
	itermove[true] = Next
	itermove[false] = Prev

	return &Select{
		Db:     db,
		Tbname: tbname,
	}
}

//空游标，整个数据库数据游标
func (s *Select) Nil() (iter iterator.Iterator) {
	iter = s.Db.NewIterator(nil, nil)
	return
}

//前缀匹配数据游标
func (s *Select) IterPrefix(key []byte) (iter iterator.Iterator) {
	iter = s.Db.NewIterator(util.BytesPrefix([]byte(key)), nil)
	return
}

//范围数据游标
func (s *Select) IterRand(b, e []byte) (iter iterator.Iterator) {
	iter = s.Db.NewIterator(&util.Range{Start: b, Limit: e}, nil)
	return
}

//定位游标
func (s *Select) IterSeekMove(key []byte) (iter iterator.Iterator, ok bool) {
	iter = s.Nil()
	ok = iter.Seek(key)
	return
}

//前缀游标
func (s *Select) IterPrefixMove(key []byte, asc bool) (iter iterator.Iterator, ok bool) { //Prefixiter
	iter = s.IterPrefix(key)
	if iter != nil {
		ok = iterFixed[asc](iter)
	}
	return
}

//范围游标
func (s *Select) IterRandMove(bkey, ekey []byte, asc bool) (iter iterator.Iterator, ok bool) {
	iter = s.IterRand(bkey, ekey)
	if iter != nil {
		ok = iterFixed[asc](iter)
	}
	return
}

/*
遍历数据库
*/
func (s *Select) ForDb(f func(k, v []byte) bool) {
	iter := s.Nil()
	for iter.Next() {
		if f(iter.Key(), iter.Value()) {
		} else {
			iter.Release()
			return
		}
	}
	iter.Release()
}

/*
遍历表数据
*/
func (s *Select) ForData(f func(k, v []byte) bool) {
	s.FindPrefixFun([]byte(s.Tbname+Split), true, f)
}

/*
遍历表所有
*/
func (s *Select) For(f func(k, v []byte) bool) {
	s.FindPrefixFun([]byte(s.Tbname), true, f)
}

/*
前缀遍历
bint 第几条开始
asc,升/降序
*/
func (s *Select) FindPrefix(key []byte, asc bool, b, count int) (kvs []KV) {
	iter, ok := s.IterPrefixMove(key, asc)
	if !ok {
		return
	}
	kvs = NewIters(iter, ok, asc, b, count).ForData()
	return
}

//前缀遍历,执行函数为参数
func (s *Select) FindPrefixFun(key []byte, asc bool, f func(k, v []byte) bool) {
	iter, ok := s.IterPrefixMove(key, asc)
	if !ok {
		return
	}
	NewIters(iter, ok, asc, 0, -1).ForDataFun(f)
}

/*
范围遍历
asc,升/降序
*/
func (s *Select) FindRand(bkey, ekey []byte, asc bool, b, count int) (kvs []KV) {
	iter, ok := s.IterRandMove(bkey, ekey, asc)
	if !ok {
		return
	}
	kvs = NewIters(iter, ok, asc, b, count).ForData()
	return
}

//范围遍历,执行函数为参数
func (s *Select) FindRandFun(bkey, ekey []byte, asc bool, f func(k, v []byte) bool) {
	iter, ok := s.IterRandMove(bkey, ekey, asc)
	if !ok {
		return
	}
	NewIters(iter, ok, asc, 0, -1).ForDataFun(f)
}

/*
定位遍历
asc,升/降序
*/
func (s *Select) FindSeek(key []byte, asc bool, b, count int) (kvs []KV) {
	iter, ok := s.IterSeekMove(key)
	if !ok {
		return
	}
	kvs = NewIters(iter, ok, asc, b, count).ForData()
	return
}

//定位遍历,执行函数为参数
func (s *Select) FindSeekFun(key []byte, asc bool, f func(k, v []byte) bool) {
	iter, ok := s.IterSeekMove(key)
	if !ok {
		return
	}
	NewIters(iter, ok, asc, 0, -1).ForDataFun(f)
}

//获取一个key的values
func (s *Select) GetValue(key []byte) (r []byte) {
	r, _ = s.Db.Get(key, nil)
	return
}

//一条主键key
func (s *Select) GetPkKey(pkvalue []byte) (r []byte) {
	bSplit := []byte(Split)
	r = JoinBytes([]byte(s.Tbname), bSplit, pkvalue)
	return
}

//一条主键key，前缀匹配，仅当主键为字符串时有效
func (s *Select) GetPkKeyLike(pkvalue []byte) (r []byte) {
	r = s.GetPkKey(pkvalue)
	r = bytes.Trim(r, Split)
	return
}

//根据主键值获取表的一条记录value（获取一个key的value）
func (s *Select) GetPKValue(fieldvalue []byte) (r []byte) { //GetRecord
	key := s.GetPkKey(fieldvalue)
	if key == nil {
		return
	}
	r = s.GetValue(key)
	return
}

//一条索引key
func (s *Select) GetIdxPrefixKey(idxfield, idxvalue, pkvalue []byte) (r []byte) {
	bSplit := []byte(Split)
	r = JoinBytes([]byte(s.Tbname), []byte(IdxSplit), idxfield, bSplit, idxvalue, bSplit, pkvalue)
	return
}

//根据主键获取表的一条记录（获取一个key的values）
func (s *Select) OneRecord(PKvalue []byte) (r []KV) { //GetOneRecord
	key := s.GetPkKey(PKvalue)
	value := s.GetValue(key)
	if value == nil {
		return
	}
	kv := KV{}
	keys := strings.Split(string(key), Split)
	pk := []byte(keys[len(keys)-1])
	kv.K = pk
	kv.V = value
	r = append(r, kv)
	return
}

//索引前缀，等于索引idxvalue
func (s *Select) GetIdxPrefix(idxfield, idxvalue []byte) (r []byte) {
	bSplit := []byte(Split)
	r = JoinBytes([]byte(s.Tbname), []byte(IdxSplit), idxfield, bSplit, idxvalue, bSplit)
	return
}

//索引前缀，索引idxvalue也前缀匹配。即是sql的like语句
func (s *Select) GetIdxPrefixLike(idxfield, idxvalue []byte) (r []byte) {
	r = s.GetIdxPrefix(idxfield, idxvalue)
	r = bytes.Trim(r, Split)
	/*
		bSplit := []byte(Split)
		r = JoinBytes([]byte(s.Tbname), []byte(IdxSplit), idxfield, bSplit, idxvalue)
	*/
	return
}

//一条组合索引key
func (s *Select) GetIdxsPrefixKey(pkvalue []byte, idxfields, idxvalues [][]byte) (r []byte) {
	bSplit := []byte(Split)
	flen, ilen := len(idxfields), len(idxvalues)
	if flen != ilen {
		return
	}
	var idxfield, idxvalue []byte
	for i := 0; i < ilen; i++ {
		idxfield = JoinBytes(idxfields[i])
		idxvalue = JoinBytes(idxvalues[i])
		if i != ilen-1 {
			idxfield = JoinBytes(idxfield, []byte(IdxSplit))
			idxvalue = JoinBytes(idxvalue, []byte(IdxSplit))
		}
	}
	r = JoinBytes([]byte(s.Tbname), []byte(IdxSplit), idxfield, bSplit, idxvalue, bSplit, pkvalue)
	return
}

/*
//根据索引获取索引记录列表
func (s *Select) GetRecordsForIdx(idxname, idxvalue []byte, b, count int) (kvs []KV) {
	key := s.getIdxPrefix(idxname, idxvalue)
	kvs = s.FindPrefix(key, true, b, count)
	return
}
*/

//根据索引记录列表返回表记录数据
//b，开始记录，count，返回条数
func (s *Select) WhereIdx(fieldname, value []byte, b, count int) (r []KV) { //GetTableRecordForIdx
	r = s.WhereIdxs(fieldname, value, b, count, true)
	/*
		//ks := s.GetRecordsForIdx(fieldname, value, b, count)
		key := s.GetIdxPrefix(fieldname, value) //ca.fid-
		kvs := s.FindPrefix(key, true, b, count)
		if kvs == nil {
			return
		}
		var keys []string
		var pk, pkval []byte
		tkv := KV{}
		for _, kv := range kvs {
			keys = strings.Split(kv.K, Split)
			pk = []byte(keys[len(keys)-1])
			pkval = s.GetPKValue(pk)
			tkv.K = string(pk)
			tkv.V = string(pkval)
			r = append(r, tkv)
		}*/
	return
}

//根据索引匹配记录列表返回表记录数据，相当于sql的like语句
//b，开始记录，count，返回条数
func (s *Select) WhereIdxLike(fieldname, value []byte, b, count int) (r []KV) { //GetTableRecordForIdx
	r = s.WhereIdxs(fieldname, value, b, count, false)
	return
}

//根据索引等于或匹配记录列表返回表记录数据
//b，开始记录，count，返回条数
func (s *Select) WhereIdxs(fieldname, value []byte, b, count int, eq bool) (r []KV) { //GetTableRecordForIdx
	gip := map[bool]func(fn, fv []byte) []byte{
		true:  s.GetIdxPrefix,
		false: s.GetIdxPrefixLike,
	}
	key := gip[eq](fieldname, value) //ca.fid-
	kvs := s.FindPrefix(key, true, b, count)
	if kvs == nil {
		return
	}
	r = s.IdxsGetRecords(kvs)
	/*
		var keys []string
		var pk, pkval []byte
		tkv := KV{}
		for _, kv := range kvs {
			keys = strings.Split(kv.K, Split)
			pk = []byte(keys[len(keys)-1])
			pkval = s.GetPKValue(pk)
			tkv.K = string(pk)
			tkv.V = string(pkval)
			r = append(r, tkv)
		}*/
	return
}

//根据索引集合获取对应的记录集合
func (s *Select) IdxsGetRecords(kvs []KV) (r []KV) {
	var keys []string
	var pk, pkval []byte
	tkv := KV{}
	for _, kv := range kvs {
		keys = strings.Split(kv.K, Split)
		pk = []byte(keys[len(keys)-1]) //最后一个值就是pk值
		pkval = s.GetPKValue(pk)
		tkv.K = string(pk)
		tkv.V = string(pkval)
		r = append(r, tkv)
	}
	return
}

//根据索引查询表记录，执行函数为参数
func (s *Select) WhereIdxFun(fieldname, value []byte, asc bool, f func(k, v []byte) bool) {
	key := s.GetIdxPrefix(fieldname, value)
	kvs := s.FindPrefix(key, asc, 0, -1)
	if kvs == nil {
		return
	}
	for _, kv := range kvs {
		if !f([]byte(kv.K), []byte(kv.V)) {
			return
		}
	}
}

//根据索引匹配查询表记录，执行函数为参数
func (s *Select) WhereIdxLikeFun(fieldname, value []byte, asc bool, f func(k, v []byte) bool) {
	key := s.GetIdxPrefixLike(fieldname, value)
	kvs := s.FindPrefix(key, asc, 0, -1)
	if kvs == nil {
		return
	}
	for _, kv := range kvs {
		if !f([]byte(kv.K), []byte(kv.V)) {
			return
		}
	}
}

//根据根据主键值获取数据
//b，开始记录，count，返回条数
func (s *Select) WherePK(value []byte) (r []KV) { //GetTableRecordForIdx
	key := s.GetPkKey(value)
	r = s.OneRecord(key)
	return
}

//根据根据主键值匹配获取数据，仅主键为字符串时有效
//b，开始记录，count，返回条数
func (s *Select) WherePKLike(value []byte, b, count int) (r []KV) { //GetTableRecordForIdx
	key := s.GetPkKeyLike(value)
	kvs := s.FindPrefix(key, true, b, count)
	if kvs == nil {
		return
	}
	r = s.IdxsGetRecords(kvs)
	//r = s.OneRecord(key)
	return
}

//根据根据主键值匹配获取数据，仅主键为字符串时有效。执行函数为参数
//b，开始记录，count，返回条数
func (s *Select) WherePKLikeFun(value []byte, b, count int, asc bool, f func(k, v []byte) bool) { //GetTableRecordForIdx
	key := s.GetPkKeyLike(value)
	kvs := s.FindPrefix(key, asc, b, count)
	if kvs == nil {
		return
	}
	for _, kv := range kvs {
		if !f([]byte(kv.K), []byte(kv.V)) {
			return
		}
	}
}

//根据根据主键范围值获取数据
//b，开始记录，count，返回条数
func (s *Select) WherePKRand(minvalue, maxvalue []byte, asc bool, b int, count int) (r []KV) { //GetTableRecordForIdx
	minkey := s.GetPkKey(minvalue)
	maxkey := s.GetPkKey(maxvalue)
	if string(maxkey) < string(minkey) {
		return
	}
	r = s.FindRand(minkey, maxkey, asc, b, count)
	return
}

//根据根据主键范围值获取数据,执行函数为参数
func (s *Select) WherePKRandFun(minvalue, maxvalue []byte, asc bool, f func(k, v []byte) bool) { //GetTableRecordForIdx
	minkey := s.GetPkKey(minvalue)
	maxkey := s.GetPkKey(maxvalue)
	if string(maxkey) < string(minkey) {
		return
	}
	s.FindRandFun(minkey, maxkey, asc, f)
}
